﻿#include "ssRedisSql.h"


namespace StarSeeker
{

ssRedisSql::ssRedisSql()
{
}

ssRedisSql::~ssRedisSql()
{
}

void ssRedisSql::Init(const char* mysqlhost, const char* mysqlacc, const char* mysqlpasswd, const char* mysqldb, unsigned int mysqlport, const char *redishost, int redisport)
{
	std::string host = mysqlhost;
	std::string user = mysqlacc;
	std::string passwd = mysqlpasswd;
	std::string db = mysqldb;
	m_mysql.open(host, user, passwd, db, mysqlport);
	m_redis.Init(redishost, redisport);
}

ssRedisSql& ssRedisSql::Tables(const char* tables)
{
	m_tables = tables;
	return *this;
}

ssRedisSql & ssRedisSql::Keys(std::initializer_list<ssAny>&& keys)
{
	m_keys.clear();
	m_keys.assign(keys);
	return *this;
}

ssRedisSql & ssRedisSql::Fields(std::initializer_list<std::string>&& fields)
{
	m_fields.clear();
	m_fields.assign(fields);
	return *this;
}

ssRedisSql & ssRedisSql::Values(std::initializer_list<ssAny>&& values)
{
	m_values.clear();
	m_values.assign(values);
	return *this;
}

void ssRedisSql::Select(std::vector<std::string>& out, char type)
{
	std::vector<std::pair<int, std::string> > outList;
	//先从redis查询
	if (type&REDIS_SQL_REDIS)
	{
		SS_REDISSQL_FORMAT_BEGIN
			m_stream << m_tables;
		for (size_t i = 1; i < m_keys.size(); i += 2)
		{
			m_stream << ':';
			WriteAny(m_keys[i], false);
		}
		SS_REDISSQL_FORMAT_END
			int ret = m_redis.HMget(outList, m_sql.c_str(), m_fields);
		if (ret)
			return;
	}
	bool ok = type & REDIS_SQL_REDIS;
	for (auto it : outList)
	{
		if (it.first==REDIS_REPLY_NIL)
		{
			ok = false;
			break;
		}
	}
	if (type&REDIS_SQL_MYSQL && !ok)
	{
		//redis没有查询到数据则去mysql查询
		SS_REDISSQL_FORMAT_BEGIN
		m_stream << "SELECT ";
		for (size_t i = 0; i < m_fields.size(); i ++)
		{
			m_stream << '`'<< m_fields[i] <<(i==m_fields.size()-1?"`":"`,");
		}
		m_stream << " FROM " << m_tables << " WHERE ";
		for (size_t i = 0; i < m_keys.size(); i += 2)
		{
			WriteAny(m_keys[i], false);
			m_stream << '=';
			WriteAny(m_keys[i+1], true);
			if (i == m_keys.size() - 2)
				m_stream << ';';
			else
				m_stream << " AND ";
		}
		SS_REDISSQL_FORMAT_END
		ssMySqlPyQuery& py = m_mysql.query(m_sql.c_str());
		int rows = py.getRowCount();
		int fields = py.getFieldCount();
		if (rows >0)
		{
			if (type&REDIS_SQL_REDIS)
			{
				//写回redis
				for (size_t i = 0; i < fields && i < outList.size(); i++)
				{
					if (outList[i].first == REDIS_REPLY_NIL)
					{
						outList[i].second = py.getStringValue(i);
					}
				}
				SS_REDISSQL_FORMAT_BEGIN
					m_stream << "HMSET " << m_tables;
				for (size_t i = 1; i < m_keys.size(); i += 2)
				{
					m_stream << ':';
					WriteAny(m_keys[i], false);
				}
				for (size_t i = 0; i < m_fields.size() && i < outList.size(); i++)
				{
					m_stream << ' ' << m_fields[i] << ' ' << outList[i].second;
				}
				SS_REDISSQL_FORMAT_END
					m_redis.Execute(m_sql.c_str());
			}
			else
			{
				for (size_t i = 0; i < fields; i++)
				{
					out.push_back(py.getStringValue(i));
				}
				return;
			}
		}
	}
	//返回
	for (auto it: outList)
	{
		out.push_back(it.second);
	}
}

void ssRedisSql::Insert(char type)
{
	if (type&REDIS_SQL_REDIS)
	{
		SS_REDISSQL_FORMAT_BEGIN
			m_stream << "INSERT INTO " << m_tables << "(";
		for (size_t i = 0; i < m_fields.size(); i++)
		{
			m_stream << (i == 0 ? "`" : ",`") << m_fields[i] << '`';
		}
		m_stream << ") VALUES(";
		for (size_t i = 0; i < m_values.size(); i++)
		{
			m_stream << (i == 0 ? "" : ",");
			WriteAny(m_values[i], true);
		}
		m_stream << ");";
		SS_REDISSQL_FORMAT_END
			m_mysql.excute(m_sql.c_str());
	}
	if (type&REDIS_SQL_MYSQL)
	{
		SS_REDISSQL_FORMAT_BEGIN
			m_stream << "HMSET " << m_tables;
		for (size_t i = 1; i < m_keys.size(); i += 2)
		{
			m_stream << ':';
			WriteAny(m_keys[i], false);
		}
		for (size_t i = 0; i < m_fields.size() && i < m_values.size(); i++)
		{
			m_stream << ' ' << m_fields[i] << ' ';
			WriteAny(m_values[i], false);
		}
		SS_REDISSQL_FORMAT_END
			m_redis.Execute(m_sql.c_str());
	}
}

void ssRedisSql::Update(char type)
{
	if (type&REDIS_SQL_REDIS)
	{
		SS_REDISSQL_FORMAT_BEGIN
			m_stream << "UPDATE " << m_tables << " SET ";
		for (size_t i = 0; i < m_fields.size() && i < m_values.size(); i++)
		{
			m_stream << '`' << m_fields[i] << "`=";
			WriteAny(m_values[i], true);
			m_stream << (i == m_fields.size() - 1 ? "" : ",");
		}
		if (!m_keys.empty())
		{
			m_stream << " WHERE ";
			for (size_t i = 0; i < m_keys.size(); i += 2)
			{
				m_stream << '`' << m_keys[i].Get<std::string>() << "`=";
				WriteAny(m_keys[i + 1], true);
				m_stream << (i < m_keys.size() - 2 ? " AND " : "");
			}
		}
		SS_REDISSQL_FORMAT_END
			m_mysql.excute(m_sql.c_str());
	}
	if (type&REDIS_SQL_MYSQL)
	{
		SS_REDISSQL_FORMAT_BEGIN
			m_stream << "HMSET " << m_tables;
		for (size_t i = 1; i < m_keys.size(); i += 2)
		{
			m_stream << ':';
			WriteAny(m_keys[i], false);
		}
		for (size_t i = 0; i < m_fields.size() && i < m_values.size(); i++)
		{
			m_stream << ' ' << m_fields[i] << ' ';
			WriteAny(m_values[i], false);
		}
		SS_REDISSQL_FORMAT_END
			m_redis.Execute(m_sql.c_str());
	}
}

void ssRedisSql::ClearStream()
{
	m_stream.str("");
	m_stream.clear();
	m_sql.clear();
}

void ssRedisSql::WriteAny(ssAny& val, bool quotes)
{
	const type_info& info = val.TypeInfo();
	if (info == typeid(std::string))
	{
		if (quotes)
			m_stream << '"' <<val.Get<std::string>() << '"';
		else
			m_stream << val.Get<std::string>();
	}
	else if (info == typeid(int))
		m_stream << val.Get<int>();
	else if (info == typeid(char))
		m_stream << val.Get<char>();
	else if (info == typeid(short))
		m_stream << val.Get<short>();
	else if (info == typeid(long long))
		m_stream << val.Get<long long>();
	else if (info == typeid(float))
		m_stream << val.Get<float>();
	else if (info == typeid(unsigned int))
		m_stream << val.Get<unsigned int>();
	else if (info == typeid(unsigned char))
		m_stream << val.Get<unsigned char>();
	else if (info == typeid(unsigned short))
		m_stream << val.Get<unsigned short>();
	else if (info == typeid(unsigned long long))
		m_stream << val.Get<unsigned long long>();
}

std::string ssRedisSql::ArrayToString(std::vector<std::string>& arr, char separator, char surround)
{
	std::string ret;
	for (size_t i = 0; i < arr.size(); i++)
	{
		if (surround>0)
		{
			ret += surround+arr[i]+surround;
		} 
		else
		{
			ret += arr[i];
		}
		if (i < arr.size() - 1)
		{
			ret += separator;
		}
	}
	return ret;
}

}
